<?php


namespace App\Services\Tools;

//生成拖动图片功能
use App\Enums\RedisKeyEnum;
use mysql_xdevapi\Exception;
use App\Exceptions\BasicException;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;

class CreateCheckImg
{
    private $tempPath   = 'temp/checkimg/';//验证图片临时存放路径
    private $valiExTime = 60;              //图片验证码过期时间
    private $exTime     = 1;               //限制请求创建图片频率  两次创建验证图片评率时间间隔$exTime
    private $phone      = '';              //管理员电话号码
    private $redisKey   = '';              //验证码存放的key


    public function __construct($phone)
    {
        $this->phone = $phone;
        $this->redisKey = sprintf(RedisKeyEnum::ADMIN_VALI_IMG, $phone);

        File::isDirectory($this->tempPath) or File::makeDirectory($this->tempPath, 0750, true, true);
    }

    /**
     * 创建动态验证码
     *
     * @return mixed
     */
    public function create()
    {
        $ttlTime = app('redis')->ttl('is_use_img:' . $this->phone);
        if ($ttlTime != -2) {//
            throw  new BasicException(10001, '验证码发送过于频繁,请' . $ttlTime . '秒后重试');
        }
        $this->delObsImg();
        app('redis')->setex('is_use_img:' . $this->phone, $this->exTime, 1);//限制创建验证图片频率

        //生成一个随机坐标，作为裁剪图片左上角的坐标。
        $x = mt_rand(100, 395);                                             //最左的坐标设置成100，为了让裁剪位置尽量出现在右边的位置，好让用户滑动一定的距离。
        $y = mt_rand(5, 85);
        $image = imagecreatefromjpeg($this->randImg());                                                                      //准备一张宽450 高140 的图片作为底片。
        $newImage = imagecreatetruecolor(50, 50);                                                                            //创建一个空白的图片。
        imagecopyresampled($newImage, $image, 0, 0, $x, $y, 50, 50, 50, 50);                                                 //把底片的一部分裁剪到空白的图片。
        $gray = imagecolorallocate($image, 230, 230, 230);                                                                   //画笔。
        imagefilledrectangle($image, $x, $y, $x + 50, $y + 50, $gray);                                                       //填充一个矩形并覆盖到裁剪的位置。
        imagesetthickness($image, 6);                                                                                        //设置画线的宽度，准备画一个粗边框的矩形在裁剪的位置，突出裁剪的位置。

        //图片临时保存地址
        imagejpeg($image, $this->tempPath . $this->phone . 'B.jpg');                                                         //保存图片，底片以大写字母A结尾。 使用后删除
        imagejpeg($newImage, $this->tempPath . $this->phone . 'S.jpg');                                                      //保存图片，裁剪的图片以大写字母B结尾  使用后删除
        imagedestroy($newImage);                                                                                             //释放内存。
        imagedestroy($image);


        $bigImgOssUrl = ObsService::putObs($this->tempPath . $this->phone . 'B.jpg', $this->tempPath . $this->phone . 'B.jpg');
        $smallImgOssUrl = ObsService::putObs($this->tempPath . $this->phone . 'S.jpg', $this->tempPath . $this->phone . 'S.jpg');


        if (!$bigImgOssUrl || !$smallImgOssUrl) {
            throw  new BasicException(10001, '图片上传失败');
        }
        $url = 'https://' . env('OBS_BUCKET') . '.' . env('OBS_ENDPOINT');                                        //获取bucket地址
        //释放内存。
        $data['x'] = $x;                                                                                          // 只能横向拉动 后台只需要验证横坐标
        $data['y'] = $y;                                                                                          //纵坐标 返回给客户端
        $data['img']['big'] = $url . '/' . $this->tempPath . $this->phone . 'B.jpg';
        $data['img']['small'] = $url . '/' . $this->tempPath . $this->phone . 'S.jpg';;
        app('redis')->setex($this->redisKey, $this->valiExTime, $data['x']);                                     //存放验证码
        $this->delImg();                                                                                         //删除本地文件

        //把坐标和名字赋值给数组。
        return $data;                                                                                            //返回数组。
    }

    public function verify($x)
    {
        if (env('USE_CHECKIMG')) {//测试服 是否跳过验证图形验证码
            return true;
        }
        $redis = app('redis');
        $rightX = $redis->get($this->redisKey);

        $redis->del($this->redisKey); //只能验证一次
        $this->delObsImg();
        if (empty($rightX)) {//没有图形验证码
            throw  new BasicException(10001, '请先获取滑动图形验证码');
        }
        if (abs($x - $rightX) > 5) {//位移偏差5个像素点以上
            throw  new BasicException(10001, '验证失败');
        }

        return true;
    }


    /**
     * 随机获取一张图片
     *
     * @return mixed
     */
    private function randImg()
    {
        $total = app('model_login_matter_img')->where('status', 1)->count() - 1;
        if ($total < 0) {
            throw  new BasicException(10001, '请先添加图片验证码素材图');
        }
        $skip = mt_rand(0, $total);
        $item = app('model_login_matter_img')->where('status', 1)->skip($skip)->take(1)->first();

        return $item->img_url;
    }

    //删除本地的图片
    private function delImg()
    {
        if (file_exists($this->tempPath . $this->phone . 'B.jpg')) {
            unlink($this->tempPath . $this->phone . 'B.jpg');
        }
        if (file_exists($this->tempPath . $this->phone . 'S.jpg')) {
            unlink($this->tempPath . $this->phone . 'S.jpg');
        }
    }


    //删除oss上文件
    private function delObsImg()
    {
        ObsService::delFileObject($this->tempPath . $this->phone . 'B.jpg');
        ObsService::delFileObject($this->tempPath . $this->phone . 'B.jpg');
    }

}



